/*
 * Copyright (c) 2009, Russell Weir
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package scripting;

class Converter {

	/**
	* Converts the provided value [v] from a Neko type to a Haxe type. Able
	* to convert Neko [hash] (aka. scripting.Dictionary) types.
	*
	* @param v Neko value to convert
	* @return Haxe encoded value
	*/
	public static function toHaxe( v : Dynamic ) : Dynamic untyped {
		switch( __dollar__typeof(v) ) {
		case __dollar__tnull: return v;
		case __dollar__tint: return v;
		case __dollar__tfloat: return v;
		case __dollar__tbool: return v;
		case __dollar__tstring: return new String(v);
		case __dollar__tarray:
			var a = Array.new1(v, __dollar__asize(v));
			for( i in 0...a.length )
				a[i] = toHaxe(a[i]);
			return a;
		case __dollar__tobject:
			if( __dollar__objgetproto(v) != null )
					throw "Can't convert class object";
			var fields = __dollar__objfields(v);
			var obj = __dollar__new(v);
			var len : Int = __dollar__asize(fields);
			for(i in 0...len)
				__dollar__objset(obj,fields[i],toHaxe(__dollar__objget(v,fields[i])));
			return obj;
		case __dollar__tabstract:
			var d = new Dictionary();
			d.h = v;
			return d;
		default:
			throw "Can't convert "+string(v);
		}
	}

	/**
	* Converts the provided value [v] from a Haxe type to a Neko type. Able
	* to convert Neko [hash] (aka. scripting.Dictionary) types, as well
	* as most other basic Haxe types.
	*
	* @param v Haxe value to convert
	* @return Neko encoded value
	*/
	public static function toNeko(v:Dynamic) : Dynamic {
		switch( Type.typeof(v) ) {
		case TNull: return v;
		case TInt: return v;
		case TFloat: return v;
		case TBool: return v;
		case TClass(c):
			if( c == String ) return #if neko untyped v.__s; #else #error #end
			switch(c) {
			case cast Array:
				var a = #if neko  untyped __dollar__amake(v.length); #else #error #end
				for( i in 0...v.length)
					a[i] = toNeko(v[i]);
				return a;
			case cast List:
				var a = #if neko untyped __dollar__amake(v.length); #else #error #end
				var i : Int = 0;
				var v : List<Dynamic> = v;
				for( e in v )
					a[i++] = toNeko(e);
				return a;
			case cast Date:
				return v.getTime();
			case cast Hash:
				return #if neko untyped v.h; #else #error #end
			case cast IntHash:
				return #if neko untyped v.h; #else #error #end
			case cast haxe.io.Bytes:
				return v.getData();
			case cast Dictionary:
				return untyped v.h;
			case cast DateObject:
				return v.toObject();
			default:
				throw "Unable to translate parameter of type " + Type.getClassName(c);
			}
		case TObject:
			#if neko
			untyped {
				var cl = v.__class__;
				if( cl != null || __dollar__objgetproto(v) != null )
					throw "Unable to translate parameter of type " + string(v);
				var fields = __dollar__objfields(v);
				var len = __dollar__asize(fields);
				var o = __dollar__new(v);
				var i = 0;
				while( i < len ) {
					__dollar__objset(o, fields[i],
						toNeko(__dollar__objget(v,fields[i])));
					i++;
				}
				return o;
			}
			#else
			#error
			#end
		case TEnum(e):
			throw "Unable to translate parameter of type enum";
		case TFunction:
			throw "Unable to translate parameter of type function";
		default:
			throw "Unable to translate parameter of type "+Std.string(v);
		}
	}
}